條件式渲染(conditional rendering) 讓我們能夠在特定的條件來動態地渲染不同的元件或內容。譬如在JavaScript 學習過的的 if… else…
statement , ternary operator
, 或&&
的邏輯運算子 等,都可以用來操作條件式渲染,這些也可以說是學習條件式渲染的必備知識。本篇會我們來看看三種條件式渲染的例子。
假設我們有一個電影的觀看清單長這樣:
若該影片已經看完了,就打「✔️ 」若還沒看就保持空白。分別用if 陳述式、我們可以怎麼做呢?
function Item({ name, isWatched }) {
let itemContent = name;
if (isWatched) {
itemContent = name + "✔️ ";
}
return (
<li className="item">
{itemContent}
</li>
);
}
export default function WatchingListList() {
return (
<section>
<h1>週末電影清單</h1>
<ul>
<Item
isWatched={true}
name="令人討厭的松子的一生"
/>
<Item
isWatched={true}
name="鬥陣俱樂部"
/>
<Item
isWatched={false}
name="猜火車"
/>
</ul>
</section>
);
}
React 的條件式渲染原則上跟JavaScript所學的條件式邏輯的寫法相當。我們將電影名稱另外於頂部宣告為變數,若「已觀看狀態」(isWatched) 為真,則在電影名稱後方加上✔️。下方的WatchingList 元件的操作,就跟我們先前在props的篇章所學過的編輯內容相同,編輯相對應的電影資訊即可。
這個方法需要留意的是,變數需要宣告在最上方,而不能連同 return 裡頭的 JSX一起放置,因為JSX只能接受表達式。(這部分看JSX的介紹篇章)
小補充:若是這串code使用原生去寫會長怎樣呢:
function Item({ name, isWatched }) {
let itemContent = name;
if (isWatched) {
itemContent = name + "✔️ ";
}
return React.createElement(
"li",
{ className: "item" },
itemContent
);
}
function WatchingList() {
return React.createElement(
"section",
null,
React.createElement("h1", null, "週末電影清單"),
React.createElement(
"ul",
null,
React.createElement(Item, {
isWatched: true,
name: "令人討厭的松子的一生",
}),
React.createElement(Item, {
isWatched: true,
name: "鬥陣俱樂部",
}),
React.createElement(Item, {
isWatched: false,
name: "猜火車",
})
)
);
}
export default WatchingList;
function Item({ name, isWatched }) {
return (
<li className="item">
{name} {isWatched && '✔'}
</li>
);
}
export default function WatchingList() {
return (
<section>
<h1>週末電影清單</h1>
<ul>
<Item
isWatched={true}
name="令人討厭的松子的一生"
/>
<Item
isWatched={true}
name="鬥陣俱樂部"
/>
<Item
isWatched={false}
name="猜火車"
/>
</ul>
</section>
);
}
這裡我們使用的是&& 運算式來處理,根據條件的真偽來決定是否顯示特定的內容。如果 isWatched
是真(true
),則會渲染 '✔'
,如果 isWatched
是假(false
),則不會渲染 '✔'
。
return (
<li className="item">
{isWatched ? name + ' ✔' : name}
</li>
);
三元運算子也是表達式,所以也可以一併寫在JSX 當中。
假設我們想做一個電影資料卡,讓使用者能夠透過片名顯示相對應的資訊,呈現出電影資料卡片的元件。原始的資料假設是這樣:
令人討厭的松子的一生 | 鬥陣俱樂部 | 猜火車 | |
---|---|---|---|
年份 | 2006年 | 1999 年 | 1996 年 |
片長 | 2 小時 10 分鐘 | 2 小時 19 分鐘 | 1 小時 34 分鐘 |
導演 | 中島哲也 | 大衛·芬奇 | 丹尼·鮑伊 |
第一個作法:
function Movie({ name }) {
let year, minutes, director;
if (name === '令人討厭的松子的一生') {
year = '2006年';
minutes = '2 小時 10 分鐘';
director = '中島哲也';
} else if (name === '鬥陣俱樂部') {
year = '1999 年';
minutes = '2 小時 19 分鐘';
director = '大衛·芬奇';
} else if (name === '猜火車') {
year = '1999 年';
minutes = '1 小時 34 分鐘';
director = '丹尼·鮑伊';
}
return (
<section>
<h1>{name}</h1>
<dl>
<dt>年份</dt>
<dd>{year}</dd>
<dt>片長</dt>
<dd>{minutes}</dd>
<dt>導演</dt>
<dd>{director}</dd>
</dl>
</section>
);
}
export default function MovieList() {
return (
<div>
<Movie name="令人討厭的松子的一生" />
<Movie name="鬥陣俱樂部" />
<Movie name="猜火車" />
</div>
);
}
做出來長這樣,其他二部片同結果,這邊就不截圖了。
這個的做法維持原始的props,並將year, minutes, director的邏輯寫在if 的句子裡。在這個步驟中year, minutes, director定義出來。再來,在return
中返回JSX樹的結構,並也在當中使用的 year, minutes, director的變數。
但若是今天想追加一部電影的話,可能操作起來就會比較繁複,我們可以試試以下的方法。
方法二:
const movies = {
令人討厭的松子的一生: {
year: '2006年',
minutes: '2 小時 10 分鐘',
director: '中島哲也'
},
鬥陣俱樂部: {
year: '1999 年',
minutes: '2 小時 19 分鐘',
director: '大衛·芬奇'
},
猜火車: {
year: '1999 年',
minutes: '1 小時 34 分鐘',
director: '丹尼·鮑伊'
},
};
function Movie({ name }) {
const info = movies[name];
return (
<section>
<h1>{name}</h1>
<dl>
<div>
<dt>年份</dt>
<dd>{info.year}</dd>
</div>
<div>
<dt>片長</dt>
<dd>{info.minutes}</dd>
</div>
<div>
<dt>導演</dt>
<dd>{info.director}</dd>
</div>
</dl>
</section>
);
}
export default function MovieList() {
return (
<div>
<Movie name="令人討厭的松子的一生" />
<Movie name="鬥陣俱樂部" />
<Movie name="猜火車" />
</div>
);
}
第二個作法首先將電影的相關資訊分別儲存在objects當中,並宣告為變數movies。再來,在Movies元件當中另外定義出info 變數的內容,也就是movies object裡的keys,再來在return 當中建立JSX的結構,變數方法使用引入object的key來指定類別。
這個作法的優勢是,可以輕易地增加,而不需變動Movie的元件設定。僅需在movies的變數中添加品項以及修改MovieList的結構即可。
當今天我們要新增一部電影資訊時,我們僅需要新增以下:
日麗: {
year: '2023 年',
minutes: '1 小時 36 分鐘',
director: '夏洛特·威爾斯'
},
<Movie name="日麗" />
至於如何做到不改動MovieList的元件結構,自動渲染資料,我們後續再談。